package io.NIO;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author 26029
 * @date 2025/4/18
 * @description
 */
public class LearnNIO {
    public static void main(String[] args) {
        // Channel - Buffer - Selector
        // Channel: IO源和目标的通道,可读可写
        // Buffer: 程序通过Buffer访问通道的数据,channel使用map()方法映射为buffer
        // 看ClientNIO.java和ServerNIO.java可知，NIO的网络编程复杂，故可以用Netty这个封装了NIO的框架

        // 阻塞同步 BIO
        // 非阻塞同步 NIO
        // 非阻塞异步 AIO

        String file_path = "D:\\project\\learnJava\\src\\main\\java\\io\\NIO\\test.txt";
        String copy_path1 = "D:\\project\\learnJava\\src\\main\\java\\io\\NIO\\test_copy1.txt";
        String copy_path2 = "D:\\project\\learnJava\\src\\main\\java\\io\\NIO\\test_copy2.txt";
        String copy_path3 = "D:\\project\\learnJava\\src\\main\\java\\io\\NIO\\test_copy3.txt";
        String copy_path4 = "D:\\project\\learnJava\\src\\main\\java\\io\\NIO\\test_copy4.txt";

        // 以下虽然是NIO的类,但是属于阻塞式IO

        // NIO 多次重复取buffer
        try (FileInputStream fis = new FileInputStream(file_path);
             FileOutputStream fos = new FileOutputStream(copy_path1);
             FileChannel inc = fis.getChannel();
             FileChannel outc = fos.getChannel()
        ) {
            ByteBuffer buffer = ByteBuffer.allocate(4);
            //多次重复"取水"的方式
            while (inc.read(buffer) != -1) {
                buffer.flip();
                outc.write(buffer);
                buffer.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // NIO 映射
        File file = new File(file_path);
        try (FileInputStream fis = new FileInputStream(file_path);
             FileOutputStream fos = new FileOutputStream(copy_path2);
             FileChannel inc = fis.getChannel();
             FileChannel outc = fos.getChannel()
        ) {
            //将 FileChannel 里的全部数据映射到 ByteBuffer 中
            MappedByteBuffer mappedByteBuffer = inc.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
            outc.write(mappedByteBuffer);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // NIO transferFrom
        try (FileInputStream fis = new FileInputStream(file_path);
             FileOutputStream fos = new FileOutputStream(copy_path3);
             FileChannel src = fis.getChannel();
             FileChannel dest = fos.getChannel()
        ) {
            dest.transferFrom(src, 0, src.size());
        } catch (Exception e) {
            e.printStackTrace();
        }

        // NIO transferTo
        try (FileInputStream fis = new FileInputStream(file_path);
             FileOutputStream fos = new FileOutputStream(copy_path4);
             FileChannel src = fis.getChannel();
             FileChannel dest = fos.getChannel()
        ) {
            long size = src.size();
            long position = 0;
            while (size > 0) {
                long count = src.transferTo(position, src.size(), dest);
                position += count;
                size -= count;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
